Skip to main content

Hooks useState

useState使用

  • React Hook函数之一,目的是在函数组件中使用状态,并且后期基于状态的修改,可以让组件更新
  • let [num,setNum] = useState(initialValue);
  • 执行usestate,传递的initialValue是初始的状态值
  • 执行这个方法,返回结果是一个数组:[状态值,修改状态的方法]
    • num变量存储的是: 获取的状态值
    • setNum变量存储的是: 修改状态的方法
  • 执行setNum(value)
    • 修改状态值为value
    • 通知视图更新
tip
  • 函数组件或者Hooks组件,不是类组件
  • 所以没有实例的概念调用组件不再是创建类的实例;
  • 而是把函数执行,产生一个私有上下文而已
  • 所以,在函数组件中不涉及this的处理
tip
  • 函数组件每一次渲染(或更新),都重新执行函数,产生一个新“私有上下文”
    • 内部的代码也需要重新执行
    • 涉及的函数需要重新的构建
      • 这些函数的作用域(函数执行的上级上下文),是每一次执行DEMO产生的闭包
    • 每一次执行函数,也会把useState重新执行,但是:
      • 执行useState第一次设置初始值,以后再执行,获取的状态是最新状态值,不是初始值
      • 返回的修改状态的方法,每一次都是返回新的方法
import React, { useState } from "react"

export default function Demo() {
let [num, setNum] = useState(0)

const handle = () => {
setNum(num + 10)
}

return (
<div>
{/* 这里注意不是Class Component中的this.handle */}
{/* 这里没有this作用域 */}
<button onClick={handle}>{num}</button>
</div>
)
}

useState设值

  • 执行一次usestate
    • 把需要的状态信息都放在对象中统一管理
    • 执行setstate方法的时候,传递的是啥值,就把状态“整体”改为啥值
      setState({
      supNum: state.supNum + 1
      })
    • 把状态值修改为 { supNum:11 }, 其他成员就丢失了
    • 并不会像类组件中的this.setstate一样,不支持部分状态的更新
tip
  • 如果只有一个变量
    let [value, setValue] = useState(0)
  • 如果有多个变量
    let [obj, setObj] = useState({
    val1: 1,
    val2: 2
    })
    const handle = () => {
    // 这里的设置必须结构后在追加
    // 否则旧的值会丢失
    setObj({
    ...obj,
    val1: 1
    })
    // 官方建议分开使用
    // let [val1, setVal1] = useState(1)
    // let [val2, setVal2] = useState(2)
    }

setState异步执行

React版本大于16
import { flushSync } from "react-dom"
let [x, setX] = useState(0)
let [y, setY] = useState(0)

const handle = () => {
//1. 这里都是异步执行的,函数组件只会render一次
setX(1)
setY(2)
//2. 也是异步的,
//但是演示版本是17的时候,render会两次,搞不清
setTimeout(()=>{
setX(1)
setY(2)
})
//2. 同步的,会render两次
flushSync(()=>{
setX(1)
})
setY(2)
}
React版本小于等于16
import { flushSync } from "react-dom"
let [x, setX] = useState(0)
let [y, setY] = useState(0)

const handle = () => {
//1. 这里都是异步执行的,函数组件只会render一次
setX(1)
setY(2)
//2. 同步的
setTimeout(()=>{
setX(1)
setY(2)
})
//2. 同步的,会render两次
flushSync(()=>{
setX(1)
})
setY(2)
}

useState的设值优化机制

let [val, setVal] = useState(0)
const handle = () => {
for(let i = 0; i < 10; i++) {
// 连续设置10次,最终得到的还是1
// 因为循环永远在函数内上下文中
// 每次循环取到的val永远是0
// react使用Object.is(val1,val2)做比较后发现val没有变化
// 就不会触发render,所以render也只会一次
setVal(val + 1)
// 但是如果setVal后使用函数回调
// 那最终的值就会是10
// 因为每次执行放到updater更新队列中的函数,每次都会被执行
setVal(prev => {
return prev + 1
})
}
}

useState设置惰化操作

import React, { useState } from "react"

const Child = (props) => {
console.log("每次state不同的改变,函数被执行")
let { x, y } = props
let [val, setVal] = useState(() => {
// 将复杂的初始话逻辑放在函数中
// 每次函数被重新执行,就无需再次计算了
console.log("这里只会被执行一次")
return x + y
})

const handle = () => {
setVal(Math.random())
}

return (
<>
<div>{val}</div>
<button onClick={handle}>click me</button>
</>
)
}

export default function Demo() {
return <Child x={1} y={2} />
}